<?php
/**
 * Created by Ido Graiman
 * Design by Ido Graiman & Andi Gutmans
 *
 * Copyright (c) 2004 - 2005 Zend Technologies Inc. All rights reserved.
 * This software is freely available under the BSD License:
 * http://www.opensource.org/licenses/bsd-license.php
 *
 * This class provide PHP / Excel connectivity through COM
 * It is meant to create a simple and easy interface for communicating between PHP and Excel.
 *
 * The following is what you can do with this class:
 * 1. Open Excel with an active workbook and one sheet
 * 2. Create a new sheet
 * 3. Set / chage the active sheet
 * 4. Set data into a sheet
 * 5. Create an Excel chart out of the data in the sheet
 * 6. Set chart type
 * 7. Set main, X axis and Y axis titles for a chart
 * 8. Set chart background color
 * 9. Remove grid between cells (done by default)
 *
 * PLEASE NOTE: This class uses PHP 5 features, and will not run on PHP4!
 *
 */
class COM_excel {
    // The following constants set the chart types
    const xlArea = 1;
    const xlLine = 4;
    const xlPie = 5;
    const xlBubbleChart = 15;
    const xlColumnClustered = 51;
    const xlColumnStacked = 52;
    const xlColumnStacked100 = 53;
    const xlColumnClustered3D= 54;
    const xlColumnStacked3D = 55;
    const xlColumnStacked1003D = 56;
    const xlBarClustered = 57;
    const xlBarStacked = 58;
    const xlBarStacked100 = 59;
    const xlBarClustered3D = 60;
    const xlBarStacked3D = 61;
    const xlBarStacked1003D = 62;
    const xlLineStacked = 63;
    const xlLineStacked100 = 64;
    const xlLineMarkers = 65;
    const xlLineMarkersStacked = 66;
    const xlLineMarkersStacked100 = 67;
    const xlPieOfPie = 68;
    const xlPieExploded = 69;
    const xlPieExploded3D = 70;
    const xlBarOfPie = 71;
    const xlXYScatter = 72;
    const xlXYScatterSmooth = 73;
    const xlXYScatterSmoothNoMarkers = 74;
    const xlXYScatterLines = 75;
    const xlAreaStacked = 76;
    const xlAreaStacked100 = 77;
    const xlAreaStacked3D = 78;
    const xlAreaStacked1003D = 79;
    const xlDoughnutExploded = 80;
    const xlRadarMarkers = 81;
    const xlRadarFilled = 82;
    
    // The following constants set the value for the default sheet direction
    const xlLTR = -5003;    // Sheet direction from left to right
    const xlRTL = -5004;    // Sheet direction from right to left
    
    private $excel_app;        // Holds the COM object for Excel
    private $workbook;        // Holds the Excel workbook
    private $sheet = array();    // Holds the collection of sheets in a workbook
    private $active_sheet;    // Holds the active sheet
    private $chartObj;        // Holds the chart object
    private $chart;            // Holds the chart itself
    private $row_start;        // Holds the first row index where the excel data starts
    private $column_start;    // Holds the first column index where the excel data starts
    private $row_index;        // Index for filling data into row
    private $column_index;    // Index for filling data into columns
    private $chartFillFormat;    // Holds the object that control's the chart's background color
    private $chartTitle;    // Holds the object controling the chart's title
    private $chartAxisX;    // Holds the object controling the chart's X axis title
    private $chartAxisY;    // Holds the object controling the chart's Y axis title
    private $_width;
    //private $_columnDimensions = array();
    
    
    /**
     * Class constructor - Create the COM object with a working sheet, and giving this sheet a name
     *
     * @param int $direction Default value is left to right, but user can set it using either xlLTR or xlRTL constants
     * @return void
     */
    public function COM_excel($direction = -5003) {
        try {
            //com.allow_dcom = true;    
            //$this->excel_app = new COM("Excel.application");
            $this->excel_app=new COM("Excel.application") or die("Cannot Initiate COM Connection"); 
            $this->excel_app->SheetsInNewWorkbook = 1;    // Setting the default number of open sheets to 1. It seems that it's not possible to set it to 0.
            $this->excel_app->DefaultSheetDirection = $direction;    // Setting the direction of sheets
            $this->workbook = $this->excel_app->Workbooks->add();    // Opening a new workbook
        } catch (com_exception $e) {
            throw new com_exception("[".__CLASS__."::".__FUNCTION__."] ".$e->getMessage()."<BR>");
        }
    }
    
    /**
     * Class destructor - closing the Excel COM object and unsetting the variable holding the COM object
     *
     */
    function __destruct() {
        $this->excel_app->Quit();
        unset($this->excel_app);
    }
    
    /**
     * Adding a new sheet to the Excel Workbook and setting it as the active sheet
     *
     * @param string $sheet_name Name of the new sheet
     */
    public function newSheet($sheet_name) {
        try {
            $this->sheet[$sheet_name] = $this->workbook->Worksheets->add();    // Creating a new sheet
            $this->sheet[$sheet_name]->activate;    // Setting new sheet as the active sheet
            $this->setActiveSheet($sheet_name);    // Keeping a 'pointer' to the active sheet
            $this->sheet[$sheet_name]->name = $sheet_name;    // Setting sheet's name
        } catch (com_exception $e) {
            throw new com_exception("[".__CLASS__."::".__FUNCTION__."] ".$e->getMessage()."<BR>");
        }
    }
        
    /**
     * Setting data into the current active sheet
     *
     * @param array $data_array An array holding the data to be set
     * @param int $start_in_row Set the starting row from which data will be inserted.
     * @param int $start_in_column Set the starting column from which data will be inserted.
     * @param string $chart_title The chart title
     * @param string $chart_description    The description of the chart
     */
    public function setChartData($data_array, $start_in_row = 1, $start_in_column = 1, $chart_title = "", $chart_description = "") {
        // Setting starting point 
        $this->row_start = $start_in_row;
        $this->column_start = $start_in_column;
        $this->row_index = $this->row_start;

        if ($chart_title) {    // If chart title is available - use it
            $this->setCellData($chart_title, 1, 1);
        }
        if ($chart_description) { // If chart description is available - use it
            $this->setCellData($chart_description, 2, 1);
        }
        
        // Inserting data into the Excel sheet
        foreach ($data_array as $row) {
            $this->column_index = $this->column_start;
            foreach ($row as $column) {
                $this->setCellData($column,$this->row_index, $this->column_index);
                $this->column_index++;
            }
            $this->row_index++;
        }
        //$this->removeCellBoundries();    // Removes the cell boundries from the excel sheet.
    }
    
    /**
     * Set data into a specific cell
     *
     * @param int $row_index The row index where the data will be set
     * @param int $column_index The column index where the data will be set
     */
    public function setCellData($data, $row_index, $column_index) {
        try {
            $cell = $this->sheet[$this->active_sheet]->Cells($row_index, $column_index);    // Select the cell to work on (Row#, Column#)
        } catch (com_exception $e) {
            throw new com_exception("[".__CLASS__."::".__FUNCTION__."] ".$e->getMessage()."<BR>");
        }                    
        $cell->value = $data;    
    }
    
    /* Tambahan */
    
    
    
    /* Tambahan */

    /**
     * Removes the grid seperating the cells in Excel
     *
     */
    private function removeCellBoundries() {
        $cellRange = $this->sheet[$this->active_sheet]->Cells;    // Getting the range of cells
        $cellInterior = $cellRange->Interior;    
        $cellInterior->ColorIndex = 2;

    }
    
    /**
     * Setting chart type for the Excel graph
     *
     * @param int $chart_type A value for the chart type (use one of the classes constants: "xl..."
     * @param int $location_X The X location where the graph should be painted
     * @param int $location_Y The Y location where the graph should be painted
     * @param int $width  Graph's width
     * @param int $height Graph's height
     */
    public function setChartType($chart_type, $location_X = 200, $location_Y = 80, $width = 400, $height = 200) {
        try {
            $this->chartObj = $this->sheet[$this->active_sheet]->chartobjects->add($location_X, $location_Y, $width, $height);        
        } catch (com_exception $e) {
            throw new com_exception("[".__CLASS__."::".__FUNCTION__."] ".$e->getMessage()."<BR>");
        }
        $this->chartObj->Activate; // place a chart in the chart object
        $this->chart = $this->chartObj->chart;
        $this->chart->ChartType = $chart_type;    // Setting the chart type
    }
    
    /**
     * Generates the Excel graph, saves the Excel worksheet into a file
     *
     * @param string $chart_title The title for the chart
     * @param string $X_title The title for the X axis of the chart
     * @param string $Y_title The title for the Y axis of the chart
     * @param int $chart_bgcolor The background color for the chart
     */
    public function generateGraph($chart_title = "", $X_title = "", $Y_title = "", $chart_bgcolor = 2,$type=1) {
        // Calculating the first and last data cells in the sheet
        $firstCell = chr(64 + $this->column_start). ($this->row_start );
        $lastCell = chr(64 + $this->column_index - 1). ($this->row_index - 1);
        
        //$firstCell = chr(64+$this->row_start ).($this->column_start) ;
        //$lastCell =  chr(64+$this->row_index - 1).($this->column_index - 1);

        
        // Setting the data area the chart uses
        $selectedArea = $this->sheet[$this->active_sheet]->range("$firstCell:$lastCell");
        $this->chart->setsourcedata($selectedArea,$type); // set the data the chart uses
        
        $this->setTitles($chart_title, $X_title, $Y_title);    // Setting chart titles
        
        // Setting the background color of the chart / graph
        $this->chartFillFormat = $this->chart->chartArea->Fill;
        $this->chartFillFormat->Visible = true;
        $this->chartFillFormat->ForeColor->SchemeColor = $chart_bgcolor;
    }

    /**
     * Setting the main, X axis and Y axis titles of the chart
     *
     * @param string $graph_title
     * @param string $X_axis_title
     * @param string $Y_axis_title
     */
    private function setTitles($graph_title, $X_axis_title, $Y_axis_title) {
        if ($graph_title) {        // Setting the chart's title
            $this->chart->HasTitle = true;
            $this->chartTitle = $this->chart->ChartTitle;
            $this->chartTitle->Text = $graph_title;
        }        
        if ($X_axis_title) {    //Setting the chart's X axis title
            $this->chartAxisX = $this->chart->Axes(1, 1);
            $this->chartAxisX->HasTitle = True;
            $this->chartAxisX->AxisTitle->Characters->Text = $X_axis_title;
        }
        if ($Y_axis_title) {    //Setting the chart's Y axis title
            $this->chartAxisY = $this->chart->Axes(2, 1);
            $this->chartAxisY->HasTitle = True;
            $this->chartAxisY->AxisTitle->Characters->Text = $Y_axis_title;
        }
    }
    
    
    /**
     * Saving Excel file
     *
     * @param string $filename The name used to save the file under
     */
    public function saveFile($filename ="COM_excel_auto_generated_file") {
        if (file_exists($filename)) {
            unlink($filename);
        }
        if (!$this->workbook->SaveAs($filename)) { // saves sheet
            throw new com_exception("Could not save excel file [".__CLASS__."::".__FUNCTION__."(".__LINE__.")]<BR>");
        }
    }
    
    /**
     * Set the active sheet to a different one
     *
     * @param string $activeSheet 
     */
    public function setActiveSheet($activeSheet) {
        $this->active_sheet = $activeSheet;
        $this->sheet[$this->active_sheet]->activate;
    }
    
    
}
